gRPC 消息类型转换
依旧是 protoreflect 包的使用
使用例:
package main
import (
"fmt"
"path/filepath"
"stgrpc/log"
"sync"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/protoparse"
"github.com/jhump/protoreflect/dynamic"
)
var (
globalProtoMap map[string]*desc.FileDescriptor
IsCached = true
lk sync.RWMutex
)
func init() {
globalProtoMap = make(map[string]*desc.FileDescriptor)
}
func getProto(path string) *desc.FileDescriptor {
lk.Lock()
defer lk.Unlock()
if IsCached {
fd, ok := globalProtoMap[path]
if ok {
log.Debugf("getProto path:%v cached \n", path)
return fd
}
}
p := protoparse.Parser{}
fds, err := p.ParseFiles(path)
if err != nil {
log.Error("getProto ParseFiles error:", err)
return nil
}
log.Debug("JsonToPb fd", fds[0])
fd := fds[0]
if IsCached {
globalProtoMap[path] = fd
}
return fd
}
// JsonToPb 传入 proto 文件的 path, proto 中对应的 message.name,js 的原始数据
// 返回生成的 proto.Marshal 的 []byte
// example:
// path := "$PROTOPATH/hello.proto"
// messageName "hello.HelloRequest"
// JsonToPb(path,"hello.HelloRequest", []byte(`{"name":"John"}`)
func JsonToPb(protoPath, messageName string, jsonStr []byte) ([]byte, error) {
log.Debug("JsonToPb protoPath", protoPath)
fd := getProto(protoPath)
msg := fd.FindMessage(messageName)
dymsg := dynamic.NewMessage(msg)
err := dymsg.UnmarshalJSON(jsonStr)
if err != nil {
log.Error("JsonToPb UnmarshalJSON error:", err)
return nil, nil
}
log.Debug("JsonToPb UnmarshalJSON dymsg", dymsg)
any, err := ptypes.MarshalAny(dymsg)
if err != nil {
log.Error("JsonToPb MarshalAny error:", err)
return nil, nil
}
log.Debug("JsonToPb marshal any", any.Value)
return any.Value, nil
}
// PbToJson 传入 proto 的 byte 数据,返回它对应的 json 数据
// example:
// path := "$PROTOPATH/helloworld.proto"
// messageName "hello.HelloRequest"
// jsonByte, err := PbToJson(path, messageName, pbByte)
func PbToJson(protoPath, messageName string, protoData []byte) ([]byte, error) {
log.Debug("PbToJson protoPath", protoPath)
fd := getProto(protoPath)
msg := fd.FindMessage(messageName)
dymsg := dynamic.NewMessage(msg)
err := proto.Unmarshal(protoData, dymsg)
log.Debug("PbToJson Unmarshal err:", err)
jsonByte, err := dymsg.MarshalJSON()
return jsonByte, err
}
// 使用例
func main() {
path, _ := filepath.Abs("./tests/hello.proto")
fmt.Println(JsonToPb(path, "hello.HelloRequest", []byte(`{"name":"John"}`)))
}